﻿namespace Example.Xml
{
    using System;
    using System.Collections.Generic;
    using System.Xml;
    using Xunit;

    public class ValidatedXmlDocumentFacts
    {
        [Fact]
        public void DefaultNamespace()
        {
            const string schema = "Default.Namespace.xsd";
            const string xml =
                "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" +
                "<foo xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"" + schema + "\">" +
                "<bar name=\"value\"/>" +
                "</foo>";

            var obj = new ValidatedXmlDocument(xml, new Uri(schema, UriKind.Relative));

            var document = (XmlDocument)obj.Document;
            if (null == document)
            {
                Assert.NotNull(document);
            }
            else
            {
                var node = document.SelectSingleNode("/foo/bar/@name");
                if (null == node)
                {
                    Assert.NotNull(node);
                }
                else
                {
                    Assert.Equal("value", node.Value);
                }
            }
        }

        [Fact]
        public void DefaultNamespace_Invalid()
        {
            const string schema = "Default.Namespace.xsd";
            const string xml =
                "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" +
                "<foo xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"" + schema + "\">" +
                "<invalid/>" +
                "</foo>";

            Assert.Throws<XmlException>(() => new ValidatedXmlDocument(xml, new Uri(schema, UriKind.Relative)));
        }

        [Fact]
        public void ImportNamespace()
        {
            const string bar = "urn:bar-schema";
            const string foo = "urn:foo-schema";
            const string schema = "Import.Namespace.Foo.xsd";
            const string xml =
                "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
                + "<foo xmlns=\"urn:foo-schema\" xmlns:imported=\"urn:bar-schema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:foo-schema\nImport.Namespace.Foo.xsd\">"
                + "<imported:bar name=\"value\"/>"
                + "</foo>";

            var obj = new ValidatedXmlDocument(xml, foo, new Uri(schema, UriKind.Relative));

            var manager = obj.ToXmlNamespaceManager(new KeyValuePair<string, Uri>("target", new Uri(foo)), new KeyValuePair<string, Uri>("imported", new Uri(bar)));

            var document = (XmlDocument)obj.Document;
            if (null == document)
            {
                Assert.NotNull(document);
            }
            else
            {
                var node = document.SelectSingleNode("/target:foo/imported:bar/@name", manager);
                if (null == node)
                {
                    Assert.NotNull(node);
                }
                else
                {
                    Assert.Equal("value", node.Value);
                }
            }
        }

        [Fact]
        public void ImportNamespace_Invalid()
        {
            const string foo = "urn:foo-schema";
            const string schema = "Import.Namespace.Foo.xsd";
            const string xml =
                "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" +
                "<foo xmlns=\"urn:foo-schema\" xmlns:imported=\"urn:bar-schema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:foo-schema\nImport.Namespace.Foo.xsd\">" +
                "<imported:invalid/>" +
                "</foo>";

            Assert.Throws<XmlException>(() => new ValidatedXmlDocument(xml, foo, new Uri(schema, UriKind.Relative)));
        }

        [Fact]
        public void TargetNamespace()
        {
            const string ns = "urn:target-schema";
            const string schema = "Target.Namespace.xsd";
            const string xml =
                "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
                + "<foo xmlns='urn:target-schema'>"
                + "<bar name=\"value\"/>"
                + "</foo>";

            var obj = new ValidatedXmlDocument(xml, ns, new Uri(schema, UriKind.Relative));

            var document = (XmlDocument)obj.Document;
            if (null == document)
            {
                Assert.NotNull(document);
            }
            else
            {
                var node = document.SelectSingleNode("/target:foo/target:bar/@name", obj.ToXmlNamespaceManager("target", new Uri(ns)));
                if (null == node)
                {
                    Assert.NotNull(node);
                }
                else
                {
                    Assert.Equal("value", node.Value);
                }
            }
        }

        [Fact]
        public void TargetNamespace_Invalid()
        {
            const string ns = "urn:target-schema";
            const string schema = "Target.Namespace.xsd";
            const string xml =
                "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" +
                "<foo xmlns='urn:target-schema'>" +
                "<invalid/>" +
                "</foo>";

            Assert.Throws<XmlException>(() => new ValidatedXmlDocument(xml, ns, new Uri(schema, UriKind.Relative)));
        }
    }
}